package com.easyioc.support;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;

import com.easyioc.config.BeanDefinition;
import com.easyioc.config.ConfigurationException;

public class SimpleBeanBuilder implements BeanBuilder {

	private static SimpleBeanBuilder instance;

	private SimpleBeanBuilder() {
	}

	public static SimpleBeanBuilder getInstance() {
		if (instance == null) {
			instance = new SimpleBeanBuilder();
		}
		return instance;
	}

	@Override
	public Map<String, Object> build(BeanDefinition[] beanDefs) {
		Map<String, Object> beans = buildBeans(beanDefs);
		setProperties(beans, beanDefs);
		return beans;
	}

	private Map<String, Object> buildBeans(BeanDefinition[] beanDefs) {
		// TODO Check beanDefs
		Map<String, Object> beans = new HashMap<String, Object>();

		for (BeanDefinition beanDef : beanDefs) {
			Class<?> beanClass = null;
			Object bean = null;
			try {
				beanClass = Class.forName(beanDef.getClassName());
				bean = beanClass.newInstance();
			} catch (ClassNotFoundException e) {
				throw new ConfigurationException("Class [ " + beanDef.getClassName()
				        + " ] can not be found. Please check you configuration.", e);
			} catch (InstantiationException e) {
				// TODO Better exception handle.
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				// TODO Better exception handle.
				throw new RuntimeException(e);
			}

			beans.put(beanDef.getBeanName(), bean);
		}

		return beans;
	}

	private void setProperties(Map<String, Object> beans, BeanDefinition[] beanDefs) {
		for (BeanDefinition beanDef : beanDefs) {
			if (beanDef.getPropDefMap().size() == 0) {
				continue;
			}

			Object bean = beans.get(beanDef.getBeanName());

			for (String propName : beanDef.getPropDefMap().keySet()) {
				String propValue = beanDef.getPropDefMap().get(propName);
				Object realPropValue = beans.get(propValue) == null ? propValue : beans.get(propValue);
				try {
					BeanUtils.setProperty(bean, propName, realPropValue);
				} catch (IllegalAccessException e) {
					// TODO Better exception handle
					throw new RuntimeException(e);
				} catch (InvocationTargetException e) {
					// TODO Better exception handle
					throw new RuntimeException(e);
				}
			}
		}
	}
}
